package yw.substart.example.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import yw.substart.example.util.Config;
import yw.substart.example.util.MapUtil;
import yw.substart.example.vo.ConfigEntity;
import yw.substart.example.vo.ParamsVo;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author lwq 2018/5/21
 * @comment
 */
@Service
public class ConfigService {
    private final Logger logger = LoggerFactory.getLogger(ConfigService.class);

    /**
     * 新增配置
     */
    public void addConfig(ConfigEntity entity) {
        entity.setCreateTime(System.currentTimeMillis());
        if (!StringUtils.isEmpty(entity.getTomcatHome())) {
            entity.setTomcatHome(entity.getTomcatHome().replaceAll("\\\\", "/"));
        }
        if (!StringUtils.isEmpty(entity.getCheckoutPath())) {
            entity.setCheckoutPath(entity.getCheckoutPath().replaceAll("\\\\", "/"));
        }
        Map map = MapUtil.transBean2Map(entity);
        map.put(ConfigEntity.STATUS, ConfigEntity.Status.WARN.getCode());
        Config.configMap.put(entity.getProjectName(), map);
        Config.write();
    }

    /**
     * 获取所有配置
     */
    public List<?> findAllConfig() {
        List<Object> list = new ArrayList<>();
        for (String key : Config.configMap.keySet()) {
            list.add(Config.configMap.get(key));
        }
        return list;
    }

    /**
     * 删除配置
     */
    public void delete(ParamsVo paramsVo) {
        if (paramsVo.getNames() == null || paramsVo.getNames().isEmpty()) return;
        for (String string : paramsVo.getNames()) {
            Config.configMap.remove(string);
            WebSocketEndpoint.sendMessageToAll("===> delete: " + string);
        }
        Config.write();
    }

    public synchronized void build(ParamsVo paramsVo) throws Exception {
        String suffix = ".war";
        boolean isJar = false;
        if (StringUtils.isEmpty(paramsVo.getProjectName()) || Config.configMap.get(paramsVo.getProjectName()) == null) {
            WebSocketEndpoint.sendMessageToAll("===> 没有找到项目配置");
            throw new Exception("没有找到项目配置");
        }
        Map map = Config.configMap.get(paramsVo.getProjectName());
        if (StringUtils.isEmpty(map.get("url"))) {
            WebSocketEndpoint.sendMessageToAll("===> 没有配置Checkout Path");
            throw new Exception("没有配置Checkout Path");
        }
        if (StringUtils.isEmpty(map.get("loginName")) && StringUtils.isEmpty(map.get("loginPass"))) {
            WebSocketEndpoint.sendMessageToAll("===> 没有配置帐号或密码");
            throw new Exception("没有配置帐号或密码");
        }
        if (StringUtils.isEmpty(map.get("tomcatHome"))) {
            WebSocketEndpoint.sendMessageToAll("===> 没有配置 Tomcat Home, 程序视为 jar 包");
            if (StringUtils.isEmpty(map.get("command"))) {
                WebSocketEndpoint.sendMessageToAll("===> 没有配置命令");
                throw new Exception("没有配置命令");
            } else {
                suffix = ".jar";
                isJar = true;
            }
        }
        String username = map.get("loginName").toString();
        String password = map.get("loginPass").toString();
        String url = map.get("url").toString();//https://192.168.0.251/svn/his/
        String checkoutPath;
        String tomcatHomePath = map.get("tomcatHome").toString();
        if (StringUtils.isEmpty(map.get("checkoutPath"))) {
            checkoutPath = "sbustart/" + map.get("projectName");
        } else {
            checkoutPath = map.get("checkoutPath").toString();
        }

        WebSocketEndpoint.sendMessageToAll(String.format("===> LoginName：%s, LoginPass：%s, Url：%s, CheckoutPath：%s", username, password, url, checkoutPath));
        logger.info("loginName: {}, loginPass: {}, url: {}, checkoutPath: {}", username, password, url, checkoutPath);


        WebSocketEndpoint.sendMessageToAll("===> svn 项目");
        //1.根据访问协议初始化工厂
        DAVRepositoryFactory.setup();
        //2.使用默认选项
        ISVNOptions isvnOptions = SVNWCUtil.createDefaultOptions(true);
        //3.初始化权限
        char[] pwd = password.toCharArray();
        ISVNAuthenticationManager isvnAuthenticationManager = SVNWCUtil.createDefaultAuthenticationManager(username, pwd);
        //4.创建SVNClientManager的实例
        SVNClientManager svnClientManager = SVNClientManager.newInstance(isvnOptions, isvnAuthenticationManager);

        long nowRevision;
        File checkFileDir = new File(checkoutPath);
        if (!checkFileDir.exists()) {
            checkFileDir.mkdirs();
            nowRevision = svnClientManager.getUpdateClient().doCheckout(SVNURL.parseURIEncoded(url), new File(checkoutPath), SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, true);
        } else {
            File[] files = checkFileDir.listFiles();
            if (files != null && files.length > 0) {
                nowRevision = svnClientManager.getUpdateClient().doUpdate(new File(checkoutPath), SVNRevision.HEAD, SVNDepth.INFINITY, true, false);
            } else {
                nowRevision = svnClientManager.getUpdateClient().doCheckout(SVNURL.parseURIEncoded(url), new File(checkoutPath), SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, true);
            }
        }
        logger.info("执行checkout操作成功，当前检出的版本号是：{}", nowRevision);
        WebSocketEndpoint.sendMessageToAll("SVN ===> 当前检出的版本号是：" + nowRevision);


        String[] mvn;
        String[] tomcatStart;
        String[] tomcatStop;

        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            mvn = new String[]{"cmd", "/c", "mvn", "-f", checkoutPath + "/pom.xml", "clean", "package"};
            tomcatStart = new String[]{"cmd", "/c", tomcatHomePath + "/bin/startup.bat"};
            tomcatStop = new String[]{"cmd", "/c", tomcatHomePath + "/bin/shutdown.bat"};
        } else {
            mvn = new String[]{"/bin/sh", "mvn", "-f", checkoutPath + "/pom.xml", "clean", "install"};
            tomcatStart = new String[]{"/bin/sh", tomcatHomePath + "/bin/startup.sh"};
            tomcatStop = new String[]{"/bin/sh", tomcatHomePath + "/bin/shutdown.sh"};
        }
        exec(mvn);//执行
        checkoutPath = checkoutPath + "/target/" + map.get("projectName") + suffix;
        if (!Files.exists(Paths.get(checkoutPath))) {
            WebSocketEndpoint.sendMessageToAll("编译后没有根据项目名称找到相应的" + suffix + "包");
            throw new Exception("编译后没有根据项目名称找到相应的" + suffix + "包");
        }
        if (!isJar) {
            tomcatHomePath = tomcatHomePath + "/webapps";
            if (!Files.exists(Paths.get(tomcatHomePath))) {
                WebSocketEndpoint.sendMessageToAll("===> Tomcat Home 无法读取");
                throw new Exception("Tomcat Home 无法读取");
            }
            tomcatHomePath = tomcatHomePath + "/" + map.get("projectName") + ".war";
            if (Files.exists(Paths.get(tomcatHomePath))) {
                Files.delete(Paths.get(tomcatHomePath));
            }
            Files.copy(Paths.get(checkoutPath), Paths.get(tomcatHomePath));

            Runtime.getRuntime().exec(tomcatStop);
            WebSocketEndpoint.sendMessageToAll("===> 正在停止 tomcat");
            Thread.sleep(3000);
            WebSocketEndpoint.sendMessageToAll("===> 正在启动 tomcat");
            Runtime.getRuntime().exec(tomcatStart);
        }


        map.put("buildTime", System.currentTimeMillis());
        Integer count = map.get("buildCount") == null ? 1 : Integer.parseInt(map.get("buildCount").toString());
        map.put("buildCount", ++count);
        map.put(ConfigEntity.STATUS, ConfigEntity.Status.SUCCESS.getCode());
        Config.configMap.put(map.get("projectName").toString(), map);
        Config.write();

        if (!StringUtils.isEmpty(map.get("command"))) {
            command(map.get("command").toString());
        }
    }

    private void exec(String... strings) throws IOException {
        Process process = Runtime.getRuntime().exec(strings);
        InputStream ins = process.getInputStream();  // 获取执行cmd命令后的信息
        BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
        String line = null;
        while ((line = reader.readLine()) != null) {
            if (line.trim().length() < 2) continue;
            logger.info(line.trim());
            WebSocketEndpoint.sendMessageToAll(line.trim());
        }
        ins.close();
        process.getOutputStream().close();  // 不要忘记了一定要关
    }

    public void startOrStop(String action, String projectName) throws Exception {
        Map map = Config.configMap.get(projectName);
        if (StringUtils.isEmpty(map.get("tomcatHome"))) {
            WebSocketEndpoint.sendMessageToAll("===> 没有找到Tomcat配置");
            throw new Exception("没有找到Tomcat配置");
        }
        String[] tomcatStart;
        String[] tomcatStop;
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            tomcatStart = new String[]{"cmd", "/c", map.get("tomcatHome") + "/bin/startup.bat"};
            tomcatStop = new String[]{"cmd", "/c", map.get("tomcatHome") + "/bin/shutdown.bat"};
        } else {
            tomcatStart = new String[]{"/bin/sh", map.get("tomcatHome") + "/bin/startup.sh"};
            tomcatStop = new String[]{"/bin/sh", map.get("tomcatHome") + "/bin/shutdown.sh"};
        }
        if ("startup".equals(action)) {
            if (os.toLowerCase().startsWith("win")) {
                Runtime.getRuntime().exec(tomcatStart).waitFor();
            } else {
                exec(tomcatStart);
            }
            WebSocketEndpoint.sendMessageToAll("===> 已启动 Tomcat");
        }
        if ("stop".equals(action)) {
            exec(tomcatStop);
            WebSocketEndpoint.sendMessageToAll("===> 已停止 Tomcat");
        }
    }

    public void command(String command) throws IOException {
        String os = System.getProperty("os.name");
        String[] commands;
        if (os.toLowerCase().startsWith("win")) {
            commands = new String[]{"cmd", "/c", command};
        } else {
            commands = new String[]{"/bin/sh", "-c", command};
        }
        WebSocketEndpoint.sendMessageToAll("===> " + Arrays.toString(commands));
        exec(commands);
    }
}
